using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Linq;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Framework;
using ESRI.ArcGIS.ArcMap;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geometry;
using BesAsm.Framework.Tracer;
using BesAsm.Framework.CommonControls;
using BesAsm.Framework.ArcGisUtilities;
using BesAsm.Framework.Reporting;
using BesAsm.Emgaats.Core;
using BesAsm.MasterData.Entities;
using BesAsm.MasterData.Data;
using BesAsm.MasterData.Services;
using BesAsm.MasterData.Gis;
using BesAsm.MasterData.CommonControls;

namespace BesAsm.Emgaats.TracerUI
{
  /// <summary>
  /// The primary user-interface for the Emgaats Tracer extension
  /// </summary>  
  [ClassInterface(ClassInterfaceType.None)]
  public partial class TracerUserControl : UserControl
  {    
    private LinkService _linkService;
    private TracerExtension _tracerExtension;
    private BindingList<LinkInfo> _startLinkInfo;
    private BindingList<LinkInfo> _stopLinkInfo;
    private PropertyWindow _propertyWindow;

    /// <summary>
    /// Initializes a new instance of the <see cref="TracerDockableWindow"/> class.
    /// </summary>
    public TracerUserControl(object hook)
    {
      InitializeComponent();

      Hook = hook;

      _startLinkInfo = new BindingList<LinkInfo>();
      _stopLinkInfo = new BindingList<LinkInfo>();
      startLinkBindingSource.DataSource = _startLinkInfo;
      stopLinkBindingSource.DataSource = _stopLinkInfo;
      _propertyWindow = new PropertyWindow();

      _tracerExtension = TracerExtension.GetExtension();      
      _tracerExtension.RebindRequired += new EventHandler(OnRebindRequired);

      _startLinkInfo.ListChanged += _startLinkInfo_ListChanged;
      _stopLinkInfo.ListChanged += _stopLinkInfo_ListChanged;
    }

    /// <summary>
    /// Host object of the dockable window
    /// </summary>
    private object Hook
    {
      get;
      set;
    }

    /// <summary>
    /// Implementation class of the dockable window add-in. It is responsible for 
    /// creating and disposing the user interface class of the dockable window.
    /// </summary>
    public class AddinImpl : ESRI.ArcGIS.Desktop.AddIns.DockableWindow
    {
      private TracerUserControl m_windowUI;

      public AddinImpl()
      {
      }

      protected override IntPtr OnCreateChild()
      {
        m_windowUI = new TracerUserControl(this.Hook);
        return m_windowUI.Handle;
      }

      protected override void Dispose(bool disposing)
      {
        if (m_windowUI != null)
          m_windowUI.Dispose(disposing);

        base.Dispose(disposing);
      }

    } 

    private void OnRebindRequired(object sender, EventArgs e)
    {
      _startLinkInfo.Clear();
      _stopLinkInfo.Clear();

      if (_tracerExtension.StartLinks != null)
      {
        _tracerExtension.StartLinks.SyncListToMap(GetLinkService());
        foreach (Link l in _tracerExtension.StartLinks)
          _startLinkInfo.Add(new LinkInfo(l));
      }

      if (_tracerExtension.StopLinks != null)
      {
        _tracerExtension.StopLinks.SyncListToMap(GetLinkService());
        foreach (Link l in _tracerExtension.StopLinks)
          _stopLinkInfo.Add(new LinkInfo(l));
      }

    }

    private void btnAddSelectedStartLinks_Click(object sender, EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      try
      {
        _tracerExtension.RefreshStartLinks();
      }
      catch (Exception ex)
      {
        string message = "Unable to add start links using current selection";
        Messenger.ReportMessage(message + ": " + ex.Message, BesAsm.Framework.Reporting.ReportableMessageType.Error);
        MessageBox.Show(message + ": " + ex.Message, message, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        Cursor = Cursors.Default;
      }
    }

    private void btnAddSelectedStopLinks_Click(object sender, EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      try
      {
        _tracerExtension.RefreshStopLinks();
      }
      catch (Exception ex)
      {
        string message = "Unable to add stop links using current selection";
        Messenger.ReportMessage(message + ": " + ex.Message, BesAsm.Framework.Reporting.ReportableMessageType.Error);
        MessageBox.Show(message + ": " + ex.Message, message, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        Cursor = Cursors.Default;
      }
    }

    private System.Collections.Specialized.StringCollection GetLinksFromUserConfig(
      LinkInputDialog _linkInput,
      System.Collections.Specialized.StringCollection configLinksCollection)
    {
      if ((configLinksCollection != null) && (configLinksCollection.Count > 0))
      {
        _linkInput.LastEntryItems = (from s in configLinksCollection.Cast<string>()
                                     select s).Reverse().ToArray<string>();
      }
      return configLinksCollection;
    }

    private static void SaveLinksCollectionToUserConfig(
      LinkInputDialog _linkInput,
      System.Collections.Specialized.StringCollection configLinksCollection,
      System.Collections.Specialized.StringCollection configLinksToSave)
    {
      StringBuilder newLinkSet = new StringBuilder();
      var orderedLines = from l in _linkInput.LineItems()
                         orderby l ascending
                         select l;
      foreach (string line in orderedLines)
      {
        if (line.Trim().Length > 0)
        {
          newLinkSet.Append(line);
          newLinkSet.Append(',');
        }
      }
      newLinkSet.Remove(newLinkSet.Length - 1, 1);
      string newLinks = newLinkSet.ToString();
      if (configLinksCollection.Contains(newLinks))
      {
        int existingStartLinksIndex = configLinksCollection.IndexOf(newLinks);
        configLinksCollection.RemoveAt(existingStartLinksIndex);
      }
      configLinksCollection.Add(newLinks);
      if (configLinksCollection.Count > Properties.Settings.Default.NumMruLinks)
        configLinksCollection.RemoveAt(0);
      configLinksToSave = new System.Collections.Specialized.StringCollection();
      configLinksToSave.AddRange(configLinksCollection.Cast<string>().ToArray());
      Properties.Settings.Default.Save();
    }

    private void btnTextEditStartLinks_Click(object sender, EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      try
      {
        using (LinkInputDialog _linkInput = new LinkInputDialog(_tracerExtension.MasterLinks)
          {
            Caption = "Select Start Links",
            Message = "Enter a list of links to use as start links"
          })
        {
          if (Properties.Settings.Default.StartLinks == null)
            Properties.Settings.Default.StartLinks =
              new System.Collections.Specialized.StringCollection();
          System.Collections.Specialized.StringCollection startLinks =
            GetLinksFromUserConfig(_linkInput, Properties.Settings.Default.StartLinks);
          if (_linkInput.ShowDialog() != DialogResult.OK)
            return;
          SaveLinksCollectionToUserConfig(_linkInput, startLinks,
            Properties.Settings.Default.StartLinks);

          int[] oids = _linkInput.Oids();
          EmgaatsLayer masterLinksLayer = _tracerExtension.MasterLinks.Layer as EmgaatsLayer;
          masterLinksLayer.SelectFeatures(oids, true);


        }
        _tracerExtension.RefreshStartLinks();
      }
      finally
      {
        Cursor = Cursors.Default;
      }
    }

    private void btnTextEditStopLinks_Click(object sender, EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      try
      {
        using (LinkInputDialog _linkInput = new LinkInputDialog(_tracerExtension.MasterLinks)
          {
            Caption = "Select Stop Links",
            Message = "Enter a list of links to use as stop links"
          })
        {
          if (Properties.Settings.Default.StopLinks == null)
            Properties.Settings.Default.StopLinks =
              new System.Collections.Specialized.StringCollection();
          System.Collections.Specialized.StringCollection stopLinks =
            GetLinksFromUserConfig(_linkInput, Properties.Settings.Default.StopLinks);
          if (_linkInput.ShowDialog() != DialogResult.OK)
            return;
          SaveLinksCollectionToUserConfig(_linkInput, stopLinks,
            Properties.Settings.Default.StopLinks);

          int[] oids = _linkInput.Oids();
          EmgaatsLayer masterLinksLayer = _tracerExtension.MasterLinks.Layer as EmgaatsLayer;
          masterLinksLayer.SelectFeatures(oids, true);
        }
        _tracerExtension.RefreshStopLinks();
      }
      finally
      {
        Cursor = Cursors.Default;
      }
    }

    private void btnClearStartLinks_Click(object sender, EventArgs e)
    {
      if (MessageBox.Show(
        "Remove all start links?", "Clear Links?",
        MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
        != DialogResult.OK)
        return;
      if (_tracerExtension.StartLinks != null)
        _tracerExtension.ArcUtils.RemoveLayers(_tracerExtension.StartLinks.Layer.Name);
      if (_tracerExtension.TraceLinks != null)
        _tracerExtension.ArcUtils.RemoveLayers(_tracerExtension.TraceLinks.Layer.Name);
    }

    private void btnClearStopLinks_Click(object sender, EventArgs e)
    {
      if (MessageBox.Show(
        "Remove all stop links?", "Clear Links?",
        MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
        != DialogResult.OK)
        return;

      if (_tracerExtension.StopLinks != null)
        _tracerExtension.ArcUtils.RemoveLayers(_tracerExtension.StopLinks.Layer.Name);
      if (_tracerExtension.TraceLinks != null)
        _tracerExtension.ArcUtils.RemoveLayers(_tracerExtension.TraceLinks.Layer.Name);
    }

    private void linkPropertiesMenuItem_Click(object sender, EventArgs e)
    {
      LinkInfo li = null;

      if (contextMenuStrip1.SourceControl == grdStartLinks)
        li = (startLinkBindingSource.CurrencyManager.Current as LinkInfo);
      else if (contextMenuStrip1.SourceControl == grdStopLinks)
        li = (stopLinkBindingSource.CurrencyManager.Current as LinkInfo);

      if (li == null)
        return;

      _propertyWindow.Title = "Properties for Link " + li.LinkName;
      _propertyWindow.Show(li.Link);

    }

    private void zoomToLinkMenuItem_Click(object sender, EventArgs e)
    {
      LinkInfo li = null;

      if (contextMenuStrip1.SourceControl == grdStartLinks)
        li = (startLinkBindingSource.CurrencyManager.Current as LinkInfo);
      else if (contextMenuStrip1.SourceControl == grdStopLinks)
        li = (stopLinkBindingSource.CurrencyManager.Current as LinkInfo);

      if (li == null)
        return;

      IFeatureClass fc = _tracerExtension.MasterLinks.Layer.FeatureClass;
      IFeature feature = fc.GetFeature(li.Link.Objectid);

      IEnvelope env = feature.ShapeCopy.Envelope;
      IMxDocument doc = (IMxDocument)ArcMap.Application.Document;
      doc.ActiveView.Extent = env;
      doc.ActiveView.Refresh();

      _tracerExtension.ArcUtils.FlashGeometry(feature.Shape, doc.FocusMap);

    }   

    private void btnDeleteStartLinks_Click(object sender, EventArgs e)
    {
      if (grdStartLinks.Selected.Rows.Count == grdStartLinks.Rows.Count)
      {
        btnClearStartLinks_Click(sender, e);
      }
      else if (grdStartLinks.Selected.Rows.Count > 0)
      {
        grdStartLinks.DeleteSelectedRows();
      }
      else if (grdStartLinks.ActiveRow != null)
      {
        grdStartLinks.Selected.Rows.Clear();
        grdStartLinks.Selected.Rows.Add(grdStartLinks.ActiveRow);
        grdStartLinks.DeleteSelectedRows();
      }
    }

    private void btnDeleteStopLinks_Click(object sender, EventArgs e)
    {
      if (grdStopLinks.Selected.Rows.Count == grdStopLinks.Rows.Count)
      {
        btnClearStopLinks_Click(sender, e);
      }
      else if (grdStopLinks.Selected.Rows.Count > 0)
      {
        grdStopLinks.DeleteSelectedRows();
      }
      else if (grdStopLinks.ActiveRow != null)
      {
        grdStopLinks.Selected.Rows.Clear();
        grdStopLinks.Selected.Rows.Add(grdStopLinks.ActiveRow);
        grdStopLinks.DeleteSelectedRows();
      }
    }

    private void grdStopLinks_AfterRowsDeleted(object sender, EventArgs e)
    {
      _tracerExtension.RefreshStopLinks(RefreshLinksOption.InternalList);
    }

    private void grdStartLinks_AfterRowsDeleted(object sender, EventArgs e)
    {
      _tracerExtension.RefreshStartLinks(RefreshLinksOption.InternalList);
    }

    private void _startLinkInfo_ListChanged(object sender, ListChangedEventArgs e)
    {
      List<int> startOids = new List<int>();
      if (e.ListChangedType == ListChangedType.ItemDeleted)
      {
        foreach (Link link in _tracerExtension.StartLinks)
        {
          if (_startLinkInfo.Count(sli => sli.LinkName == link.LinkName) > 0)
          {
            startOids.Add(link.Oid);
          }
        }
        int[] startOidsToLayer = startOids.ToArray();
        _tracerExtension.StartLinks.Layer.SelectFeatures(startOidsToLayer, true);
        _linkService = new LinkService();
        _tracerExtension.StartLinks.SyncListToSelection(_linkService);
      }
    }

    private void _stopLinkInfo_ListChanged(object sender, ListChangedEventArgs e)
    {
      List<int> stopOids = new List<int>();
      if (e.ListChangedType == ListChangedType.ItemDeleted)
      {
        foreach (Link link in _tracerExtension.StopLinks)
        {
          if (_stopLinkInfo.Count(sli => sli.LinkName == link.LinkName) > 0)
          {
            stopOids.Add(link.Oid);
          }
        }
        int[] stopOidsToLayer = stopOids.ToArray();
        _tracerExtension.StopLinks.Layer.SelectFeatures(stopOidsToLayer, true);
        _linkService = new LinkService();
        _tracerExtension.StopLinks.SyncListToSelection(_linkService);

      }
    }

    private LinkService GetLinkService()
    {
      if (_linkService == null)
        _linkService = new LinkService();
      return _linkService;
    }

    private void btnPerformTraceDropDown_Click(object sender, EventArgs e)
    {
      PerformTrace();
    }

    private void PerformTrace()
    {
      _tracerExtension.Trace();
    }

    private void PerformTraceAndZoom()
    {
      PerformTrace();

      IFeatureLayer traceLayer = _tracerExtension.TraceLayer;
      ArcGisUtils arcGisUtils = new ArcGisUtils(ArcMap.Application);
      arcGisUtils.ZoomToLayer(traceLayer);
    }

    private void ultraToolbarsManager1_ToolClick(object sender, Infragistics.Win.UltraWinToolbars.ToolClickEventArgs e)
    {
      switch (e.Tool.Key)
      {
        case "Perform Trace and Zoom":    // ButtonTool
          PerformTraceAndZoom();
          break;
      }
    }

    private void ultraButton1_Click(object sender, EventArgs e)
    {
      UID u = new UIDClass();
      try
      {
        u.Value = "esriArcMapUI.SelectFeaturesTool";
      }
      catch (Exception ex)
      {
        System.Diagnostics.Debug.WriteLine(ex.Message);
      }
      ICommandItem cmdItem = ArcMap.Application.Document.CommandBars.Find(u, false, false);
      cmdItem.Execute();
    }

  }
}
